package com.spz.demo.singleboot.exception;

import com.spz.demo.singleboot.util.BusinessUtil;
import com.spz.demo.singleboot.util.ExceptionUtil;
import com.spz.demo.singleboot.vo.Code;
import com.spz.demo.singleboot.vo.Response;
import com.spz.demo.singleboot.exception.custom.RoleException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.Set;

/**
 * 一些自定义的异常处理
 *
 * @author spz
 */
@Slf4j//(topic = "SYS_LOG")
@ControllerAdvice//拦截异常
@Component
public class GlobalExceptionHandler {

    /**
     * hibernate 参数校验出错会抛出 ConstraintViolationException 异常
     * 在此方法中处理，将错误信息输出
     * @param exception
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)//指定是哪个异常
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Response hibernateViolationExceptionHandle(ValidationException exception) {
        String errorInfo = "";
        ConstraintViolationException exs = (ConstraintViolationException) exception;
        Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
        for (ConstraintViolation<?> item : violations) {
            errorInfo = errorInfo + "[" + item.getMessage() + "]";
        }
        return Response.error(Code.DEFAULT_PARAMS_ERROR,errorInfo);
    }

    /**
     * 拦截 Shiro 的 AuthenticationException 异常
     * @param e
     * @return
     */
    @ExceptionHandler(AuthenticationException.class)//指定是哪个异常
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Response shiroAuthException(AuthenticationException e) {

        // 账号不存在 或 密码错误 异常
        // 两个异常放一起是为了防止暴力破解
        if(e instanceof IncorrectCredentialsException || e instanceof UnknownAccountException){
            return Response.error(Code.ACCOUNT_PASS_ERROR);
        }

        return Response.error(Code.ROLE_ERROR,e.getCause().getMessage());
    }

    /**
     * 拦截自定义的 RoleException 异常
     * 一般在登录时出现此异常
     * @param e
     * @return
     */
    @ExceptionHandler(RoleException.class)//指定是哪个异常
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Response roleException(RoleException e) {
        return Response.error(Code.ROLE_ERROR,e.getCause().getMessage());
    }

    /**
     * 拦截自定义的基类异常
     * @param e
     * @return
     */
    @ExceptionHandler(BasicException.class)//指定是哪个异常
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Response customerException(BasicException e) {
        log.error("捕获异常：" + ExceptionUtil.getDetailExceptionMsg(e));//具体异常打印到日志
        return Response.error(Code.DEFAULT_ERROR,e.getMessage());// 返回基本报错信息回前台
    }

    /**
     * 拦截 Exception 异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)//指定是哪个异常
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Response exception(Exception e) {
        log.error("捕获异常：" + ExceptionUtil.getDetailExceptionMsg(e));//具体异常打印到日志
        return Response.error(Code.UNKNOWN_ERROR,"捕获异常：" + e.getMessage());
    }
}
